﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace SharpSoft.Maths
{
    /// <summary>
    /// 三角形辅助工具
    /// </summary>
    public class TrigonHelper
    {
        /// <summary>
        /// 计算测试点是否在三角形内部
        /// <see cref="https://www.gamedev.net/forums/topic/295943-is-this-a-better-point-in-triangle-test-2d/"/>
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <param name="v3"></param>
        /// <param name="test"></param>
        /// <returns></returns>
        /// <remarks>
        /// 顺时针／逆时针判定法。  该方法要求点的顺序是顺时针或逆时针的，如果是顺时针的点，沿着3条边走，如果目标点P在三角形内，那么P始终在边的右侧。
        /// 同理，如果是逆时针的话，目标点p应该始终在边的左侧。 
        /// 例：逆时针的三个点abc，判断abXap , bcXbp , caXcp,如果这三个向量叉积的Z值都同向，并且都为负的话（左手系），说明p点在三角形内部。
        /// （Unity使用的是右手坐标系，也是右手法则，逆时针旋转，大拇指向旋转的正方向）  
        /// </remarks>
        public static bool IsInsideTrigon(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
        {
            var v0 = C - A;
            var v1 = B - A;
            var v2 = P - A;

            var dot00 = Vector2.Dot(v0, v0);
            var dot01 = Vector2.Dot(v0, v1);
            var dot02 = Vector2.Dot(v0, v2);
            var dot11 = Vector2.Dot(v1, v1);
            var dot12 = Vector2.Dot(v1, v2);

            var inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);

            var u = (dot11 * dot02 - dot01 * dot12) * inverDeno;
            if (u < 0 || u > 1) // if u out of range, return directly
            {
                return false;
            }

            var v = (dot00 * dot12 - dot01 * dot02) * inverDeno;
            if (v < 0 || v > 1) // if v out of range, return directly
            {
                return false;
            }

            return u + v <= 1;

        }
    }
}
